Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: libiabanuelos7-sudo/datatracker
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: ietf-tools/datatracker
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 20 commits
  • 76 files changed
  • 9 contributors

Commits on Aug 5, 2026

  1. Configuration menu
    Copy the full SHA
    6fcc7d8 View commit details
    Browse the repository at this point in the history

Commits on Aug 12, 2026

  1. feat: declare the RFC Editor info page canonical for RFCs and subseri…

    …es (ietf-tools#11481)
    
    * feat: declare the RFC Editor info page canonical for RFCs and subseries
    
    The authoritative home of an RFC, and of a bcp/std/fyi subseries document, is
    the RFC Editor's info page, so declare that page canonical on the datatracker
    pages that render the same document. This deliberately consolidates search
    results on rfc-editor.org for those documents.
    
    Documents of other types keep the self-referential canonical they had. The
    subseries pages declared no canonical at all before this, as they do not
    include opengraph.html, so they gain a pagehead block.
    
    * fix: redirect /doc/html/{bcp,std,fyi}N to the trailing-slash info URL
    
    The RFC Editor serves its info pages with a trailing slash, so the bcp and std
    redirects were sending visitors to a URL that redirects again. Add the missing
    fyi equivalent while here.
    rjsparks authored Aug 12, 2026
    Configuration menu
    Copy the full SHA
    d20c847 View commit details
    Browse the repository at this point in the history
  2. fix: add email validation to secr announcement form (ietf-tools#11245)

    * fix: add email validation to secr announcement form
    
    * fix: add cc field list to the validation logic
    
    * tests: add cc test
    
    * fix: handle validation for multiple cc fields
    
    * tests: add form email field tests
    noralmaani authored Aug 12, 2026
    Configuration menu
    Copy the full SHA
    cb2afdd View commit details
    Browse the repository at this point in the history

Commits on Aug 13, 2026

  1. Configuration menu
    Copy the full SHA
    2f370df View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    8fd98eb View commit details
    Browse the repository at this point in the history
  3. fix: prevent slide upload by participants after session (ietf-tools#1…

    …0582) (ietf-tools#11258)
    
    * fix: prevent slide upload by participants after session
    
    * Correct display of Upload Slides button on agenda materials popup
    
    * Style improvement
    
    Co-authored-by: Jennifer Richards <jennifer@staff.ietf.org>
    
    * test: fix failing tests
    
    * test: test_is_past()
    
    * fix: handle corner cases
    
    * test: is_past() gates proposing slides
    
    ---------
    
    Co-authored-by: Jennifer Richards <jennifer@staff.ietf.org>
    jimfenton and jennifer-richards authored Aug 13, 2026
    Configuration menu
    Copy the full SHA
    bc04115 View commit details
    Browse the repository at this point in the history
  4. Configuration menu
    Copy the full SHA
    9b83417 View commit details
    Browse the repository at this point in the history
  5. Configuration menu
    Copy the full SHA
    2e89adb View commit details
    Browse the repository at this point in the history
  6. perf: improve /doc/search performance (ietf-tools#11507)

    * perf: stop the document search author and name filters cross-multiplying
    
    Searching by author ORed five lookups into a single filter(), spanning
    documentauthor -> person -> {alias,email} and rfcauthor -> person ->
    {alias,email}. Because they share one filter() call, Django cannot split
    them across separate joins, so the two author paths cross-multiply. The
    name filter added a third multi-valued relation, targets_related, to the
    same OR group.
    
    For /doc/search/?author=Barry+Leiba&by=author&name=rfc&rfcs=on that meant
    18 joins and roughly 126M intermediate rows to return 32 documents: 118
    seconds, and 745M shared buffer hits. The planner estimated 7 rows for
    the node that produced 41.9M, so it committed to nested loops; the
    misestimate is not fixable by tuning, only by removing the fan-out. The
    same search with drafts included did not complete at all, failing with
    "could not resize shared memory segment ... No space left on device".
    
    Resolve the author text to people first and match documents by primary
    key, and reach related documents through a pk subquery instead of the
    targets_related join. Measured 118s -> 0.14s on the same data.
    
    Skip the draft-state clause when no draft state is allowed. On the
    types-driven path that excludes nothing -- "draft" is only in `types`
    when at least one draft state is allowed -- while still emitting two
    joins that multiplied rows in the rest of the query. The all_types path
    does not consult `types`, so there it keeps excluding drafts explicitly.
    When the clause does apply, express it as a subquery too: a document has
    several state rows, so joining duplicated every non-draft that passed the
    other half of the OR.
    
    That was the only thing requiring the trailing distinct(), so drop it.
    It was applied to the full column list, which prepare_document_table
    widens further with select_related(), forcing a sort over 72 columns
    including abstract, group description and person biography -- about 1GB
    of temp spill on the search above.
    
    Verified against a full-size database: 26 query shapes produce identical
    result sets with no duplicate rows, and the all_types path matches too,
    including the case where no checkbox is set and drafts must be excluded.
    
    * fix: give each document search its own cache entry
    
    The search cache key was built from request.GET via QueryDict.items(),
    which returns only the last value of a multi-valued key. doctypes is a
    ModelMultipleChoiceField, so
    
        ?doctypes=charter&doctypes=statchg&name=foo
        ?doctypes=statchg&name=foo
    
    hashed to the same key while returning different result sets, and each
    could be served the other's results.
    
    Derive the key from the validated cleaned_data instead. That fixes the
    collision and also stops equivalent spellings of the same search from
    splitting the cache -- "on" and "1" for a checkbox now agree, and the
    order the values of a multi-valued field arrive in no longer matters.
    
    'sort' stays out of the key, as before: prepare_document_table applies
    the requested sort on every request.
    
    * perf: cache document search result ids rather than prepared documents
    
    The search view cached the fully prepared Document objects: their
    prefetch caches, latest_event_cache DocEvents, milestones, sessions and
    select_related Person and Group rows. A 200-row all-types search pickles
    to 1.28MB, over memcached's default 1MB item limit -- which is why
    LenientMemcacheCache exists to swallow "object too large for cache". The
    searches most worth caching were therefore never cached, and recomputed
    on every request.
    
    Cache the matching document ids and re-prepare on a hit. The payload
    becomes a few hundred integers.
    
    This also fixes a second problem. 'sort' is not part of the cache key,
    but prepare_document_table sorts in place, so a cached entry carried
    whatever order it was first computed with and clicking a column header
    could return the previous ordering. Re-preparing on each request applies
    the requested sort every time.
    
    Re-preparing does mean the rows arrive in whatever order the pk lookup
    returns, and prepare_document_table's sort is stable, so tie-heavy sort
    keys -- ipr, status and ad -- would render a page differently depending
    on whether it hit the cache. Order the lookup the same way
    retrieve_search_results does. That ordering is now ('-time', 'pk'):
    `time` alone is not a total order, documents sharing a timestamp to the
    second are common, and without the tie-break both the set of rows kept by
    the max_results truncation and the order equal sort keys fall back to
    vary between executions. This replaces arbitrary ordering with stable
    ordering; it does not reorder anything that was previously well defined.
    
    Use "is None" rather than a falsy test so an empty result set is a cache
    hit instead of being recomputed every time.
    
    * fix: make fill_in_telechat_date actually fill in the telechat date
    
    The two lines that stored the result were commented out, so the function
    ran a query over TelechatDocEvent, walked the results and threw them
    away. Every row of the document table then called doc.telechat_date()
    itself, one latest_event() query apiece -- 103 of them on a 187-row group
    search -- and the five IESG views that call this before filtering on
    doc.telechat_date() paid the same per-document cost.
    
    Restore the assignment, and set the remaining documents to None so a
    document with no telechat event does not fall through to the method
    either. Order by ('-time', '-id') to match Document.latest_event(), so
    the precomputed value equals what the method returns; a test covers that
    equality, because a mismatch here silently drops documents off a telechat
    agenda.
    
    wrap_value becomes a module-level callable class rather than returning a
    lambda. ietf.doc.views_search.recent_drafts pickles prepared documents
    into the slowpages cache, which is file-based in production, so a lambda
    would have made /doc/recent/ raise "AttributeError: Can't get local
    object". Dev and test configure that cache as a DummyCache, which never
    serializes, so nothing in the suite would have caught it -- hence the
    accompanying picklability test.
    
    It also defines __hash__ alongside __eq__, which Python would otherwise
    set to None -- a method it stands in for is hashable.
    
    * perf: look up review assignments once for the whole document table
    
    fill_in_document_table_attributes called review_assignments_to_list_for_docs
    with a single-element list from inside its per-document loop, even though
    the helper takes a list and is built to answer for many documents at
    once. Each call ran a breadth-first walk of the replaces graph -- one
    query per level -- plus its own assignment query. On a 187-row group
    search that was 342 queries where three suffice.
    
    Hoist the call out of the loop and index the result by document name.
    
    The assignment queryset only prefetched "result" while the table renders
    the request's document, team and type and links to the review itself, so
    each assignment shown cost several more queries. select_related them.
    That also benefits the other two callers, ietf.doc.views_doc and
    ietf.iesg.agenda.
    
    * perf: batch the document relations the search table renders
    
    Each row of the document table reads several relations: friendly_state
    asks for the replacements and whether the draft became an RFC, the RFC
    branch asks what subseries the document is part of, and the date column
    asks what it replaces. Document.related_that and related_that_doc run a
    query apiece, so those were roughly 370 queries on a 187-row search.
    
    The IPR column was worse. Document.related_ipr collects disclosures
    against the document and everything it transitively obsoletes or
    replaces, and it walks that graph with all_relations_that_doc, which
    issues a query per node it visits, per document -- another 244.
    
    Fetch all of it up front: two queries for the relations the table reads,
    and a breadth-first walk of the obs/replaces graph for the whole result
    set at once, one query per level of depth plus one for the disclosures.
    
    related_that and related_that_doc consult a per-instance cache when one
    has been seeded. The cache is read-only and opt-in: nothing else in the
    tree sets those attributes, and an unseeded document falls through to the
    original query, so every other caller is unaffected.
    
    related_ipr is attached wrapped rather than as a bare list so the
    attribute stays callable like the method it shadows; templates auto-call
    either way, but a bare list would make doc.related_ipr() a TypeError for
    any Python caller handed a prepared document.
    
    * perf: batch the person lookups behind the AD and shepherd columns
    
    select_related("ad") gives every row of the document table its own Person
    instance, so the memoisation on Person.email() never helps across rows.
    person_link also asked, per row, whether the person's name is recorded as
    one of their aliases. Between them that was 178 queries on a 187-row
    search, plus more for each action holder listed.
    
    Add Person.has_alias_for_name(), which is the expression person_link had
    inline, memoised per instance and dropped in save() where the aliases
    change. Seed it, and Person.email()'s own cache, for the ADs, shepherds
    and action holders of a whole result set at once: the emails come from
    prefetches, so only the aliases need a query, and one covers all of them.
    
    Action holders are only read when the document has them enabled, which is
    the condition the template applies too, so callers that skipped the
    prefetch pay nothing extra.
    
    person_link is used by 62 templates. Every call site passes a Person, and
    plain_name() is evaluated before the changed line, so anything else would
    already have failed there.
    
    The address sort key is casefolded because Email.address is a CICharField,
    so the database orders it case-insensitively and a byte-wise Python sort
    could otherwise pick a different address than Person.email() would.
    
    * perf: stop the document table refetching rows it already has
    
    Six small fixes to fill_in_document_table_attributes and its querysets,
    each independently visible in a query trace of a search page.
    
    The latest-event cache selected every published_rfc, ballot-position,
    started_iesg_process and new_revision event for the whole result set,
    ordered ascending, and let later rows overwrite earlier ones in Python. A
    draft routinely has dozens of new_revision events. Use DISTINCT ON to
    fetch one row per (document, type) instead.
    
    Documents with no ballot event at all had no `ballot` attribute, so
    ballot_icon fell back to doc.active_ballot() -- a query apiece. Default it
    to None, which is exactly what that fallback returns: same event types,
    same ('-time', '-id') ordering, same created_ballot test.
    
    The milestone sort key read m.state.slug when m.state_id already is the
    slug, costing a query per milestone. The obsoleted-by and updated-by
    lookup select_related only the target, then read rel.source.
    
    select_related "type", which search_heading renders for every non-draft
    row, and "shepherd__person", which the shepherd column reads. Prefetch
    the action holders and their emails, which the status column reads.
    
    Drop the "iprdocrel_set" prefetch: nothing uses it. The table renders
    doc.related_ipr, which builds its own queryset, and Document.ipr() calls
    .filter() on the related manager, which discards a prefetch and requeries
    anyway -- ?sort=ipr measured identical at 187 per-row queries with and
    without it.
    
    * test: guard the document table against per-row queries
    
    Rendering the table fills every attribute in for the whole result set at
    once, so the number of queries should not depend on the number of rows.
    Assert that directly: render a group search, triple the result set, and
    require the query count not to move. A lookup that slips back into the
    per-row path adds at least one query per new document, so it fails loudly
    rather than quietly costing a few hundred queries a page.
    
    Written as an invariant rather than a fixed number so it does not need
    updating whenever the fixed setup cost changes.
    
    * chore: use QuerySetAny for isinstance check
    
    Avoids mypy lint
    
    ---------
    
    Co-authored-by: Jennifer Richards <jennifer@staff.ietf.org>
    rjsparks and jennifer-richards authored Aug 13, 2026
    Configuration menu
    Copy the full SHA
    0c1ffae View commit details
    Browse the repository at this point in the history
  7. Configuration menu
    Copy the full SHA
    01f0bff View commit details
    Browse the repository at this point in the history
  8. Configuration menu
    Copy the full SHA
    22c808c View commit details
    Browse the repository at this point in the history

Commits on Aug 14, 2026

  1. fix: accept std "To" addrs in announcement tool (ietf-tools#11524)

    * fix: accept std "To" addrs in announcement tool
    
    * fix: fix failing tests
    
    Some code changes, some test changes.
    jennifer-richards authored Aug 14, 2026
    Configuration menu
    Copy the full SHA
    95edec0 View commit details
    Browse the repository at this point in the history

Commits on Aug 17, 2026

  1. chore: drop unused config + unused k8s file (ietf-tools#10828)

    * chore: remove obsolete files in k8s/
    
    * chore: remove unused/OBE API signing key
    
    * chore: lint
    
    * chore: remove GITHUB_BACKUP_API_KEY setting
    
    * docs: restore/rename the example secrets.yaml
    jennifer-richards authored Aug 17, 2026
    Configuration menu
    Copy the full SHA
    b386056 View commit details
    Browse the repository at this point in the history

Commits on Aug 19, 2026

  1. Configuration menu
    Copy the full SHA
    76a9af9 View commit details
    Browse the repository at this point in the history

Commits on Aug 20, 2026

  1. feat: show rfc editor queue status on search result rows (ietf-tools#…

    …11549)
    
    * feat: show rfc editor queue status on search result rows
    
    * docs: commentary on prefetch states and tags for iesg agenda
    rjsparks authored Aug 20, 2026
    Configuration menu
    Copy the full SHA
    3f84a81 View commit details
    Browse the repository at this point in the history
  2. feat: Person UUID, related OIDC claims, and apis (ietf-tools#11415) (i…

    …etf-tools#11597)
    
    * feat: UUIDs as person identifiers
    
    * feat: person uuid oidc claims and apis
    
    * chore: ruff ruff
    
    * fix: adjust how push is triggered
    
    * fix: keep the mypy ignore on the person model import
    
    Reformatting the import into a parenthesized block moved the ignore comment to
    the closing paren. mypy reports the simple_history HistoricalPerson and
    HistoricalEmail attribute errors against the 'from ... import (' line, so the
    comment has to sit there to suppress them.
    
    * refactor: register the anycase_uuid converter in the root URLconf
    
    Registering it in ietf/utils/converters.py made importing that module a side
    effect, and Django refuses to register a converter twice, so naming the
    converter from a second URLconf was a latent error. Define it there, register it
    once in ietf/urls.py before urlpatterns names it.
    
    * fix: create a Person and its primary UUID atomically
    
    A Person with no primary UUID cannot be named to any external system, so the
    create and the assign_primary_uuid() that follows it have to succeed or fail
    together. Covers all three production creation sites, including the draft
    submission one, and wraps the surrounding aliases and nominee email so a
    failure part way leaves nothing half-built.
    
    * refactor: give each UUID batch endpoint a single response serializer
    
    The resolved/unknown split needed a PolymorphicProxySerializer, which is an
    annotation helper rather than a real serializer, so the endpoints hand-built
    dicts and told consumers not to infer the outcome from which fields were
    present. Use one entry serializer per endpoint instead, discriminated on status,
    with the identifier fields nullable and always present, and actually serialize
    responses through it so the schema cannot drift from what is returned.
    
    Drops the ResolvedStatusEnum/UnknownStatusEnum overrides that existed only to
    keep the two single-valued status enums apart - there is now one StatusEnum. The
    entry fields are not read_only because read_only implies required=False, which
    left a generated client treating even status as optional.
    
    Also annotates retrieve with @extend_schema_view rather than overriding it just
    to call super().
    
    * refactor: serve the pk-to-UUID conversion from a plain APIView
    
    Routing this lookup through a GenericViewSet forced the handler to be named
    create, because that is what SimpleRouter maps POST to on a collection route.
    Nothing is created: the view returned 200 while drf-spectacular inferred 201
    from the action name, so the schema advertised a status code the endpoint never
    sends and a generated client would treat the real response as unexpected.
    
    An APIView.post() returns 200 with no annotation gymnastics. The viewset was
    buying nothing else - no retrieve, no mixins, and an empty queryset. api_key
    auth is unaffected, since HasApiKey just reads api_key_endpoint off the view.
    
    The URL is unchanged. Its name loses the router's -list suffix, and the schema
    test now checks the declared success codes so this cannot drift again.
    
    * feat: carry both UUID claims in one OIDC scope
    
    Splitting the current identifier and the superseded ones across two scopes was
    finer-grained than any consumer needs - there is no case for granting one and
    not the other, and the prior list is far too short for response size to matter.
    
    Also corrects the scope description, which claimed the prior list included the
    identifier in use now. It does not, and datatracker_uuid is where that lives.
    
    * fix: check for exactly one primary UUID, not just one or more
    
    The job logged that every Person has exactly one primary while only looking for
    Persons with none. The partial unique constraint should make more than one
    impossible, so finding one means the data is grossly inconsistent and worth
    reporting - and ensure_primary_uuid() cannot repair that case, since it would be
    picking a survivor arbitrarily, so it is reported and skipped rather than
    silently 'fixed'. Same change in the base-test-data check.
    
    * fix: let the UUID push enqueue use the default retry policy
    
    Celery's default is three attempts over well under a second, which is cheap
    enough on the request path that changed the UUID set and is the difference
    between riding out a broker blip or failover and dropping the push on the floor.
    The broker-error catch still keeps an outright outage from failing the
    datatracker operation.
    
    * chore: add dev API tokens for the person UUID endpoints
    
    Neither endpoint had an APP_API_TOKENS entry in the container config, so every
    call to them from a dev environment got a 403.
    
    * test: build Person UUIDs with the factories and read them through the accessors
    
    PersonFactory now makes its Person's primary UUID with PersonUUIDFactory instead
    of calling assign_primary_uuid() itself, so all UUID handling in tests goes
    through the factories. PersonFactory(primary_uuid=False) covers the
    no-UUIDs-at-all case, which no production path can reach, replacing the tests
    that created a Person and then deleted its UUID rows.
    
    Tests now assert through Person.primary_uuid and Person.prior_uuids rather than
    querying uuids directly, so the accessors are the example to copy. Direct
    queries remain only where they are the point: the test proving the accessors
    agree with the rows, and setup that deliberately builds inconsistent state.
    
    Also drops the retry kwarg assertion that went with the old retry=False.
    
    * fix: order prior_uuids deterministically
    
    A merge stamps every UUID it moves with the same time, so ordering the prior list
    on time alone left the order undefined in exactly the case where there is more
    than one prior. Break ties on the UUID, which also makes the claim that
    uuid_sets_for() matches this accessor true - it was already ordering on both.
    
    * docs: correct why prior_uuids breaks ties on the uuid
    
    The previous comment justified the tie-break by claiming a merge gives every
    UUID it moves the same timestamp. It does not: merge_persons() moves them with a
    queryset update that names only person and primary, and PersonUUID.time is a
    per-row default with no auto_now, so each keeps its original timestamp.
    
    The tie-break stands on narrower ground - it makes the order total instead of
    leaving equal timestamps to the database, and matches the ordering uuid_sets_for()
    already used - so only the comment changes.
    
    * test: clear over-zealous concerns about API return values
    
    ---------
    
    Co-authored-by: Robert Sparks <rjsparks@nostrum.com>
    jennifer-richards and rjsparks authored Aug 20, 2026
    Configuration menu
    Copy the full SHA
    df4394a View commit details
    Browse the repository at this point in the history
  3. chore(deps-dev): bump npm-check-updates in /playwright in the npm gro…

    …up (ietf-tools#11529)
    
    Bumps the npm group in /playwright with 1 update: [npm-check-updates](https://github.com/raineorshine/npm-check-updates).
    
    
    Updates `npm-check-updates` from 23.0.1 to 23.0.2
    - [Release notes](https://github.com/raineorshine/npm-check-updates/releases)
    - [Changelog](https://github.com/raineorshine/npm-check-updates/blob/main/CHANGELOG.md)
    - [Commits](raineorshine/npm-check-updates@v23.0.1...v23.0.2)
    
    ---
    updated-dependencies:
    - dependency-name: npm-check-updates
      dependency-version: 23.0.2
      dependency-type: direct:development
      update-type: version-update:semver-patch
      dependency-group: npm
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Aug 20, 2026
    Configuration menu
    Copy the full SHA
    f8f49c5 View commit details
    Browse the repository at this point in the history
  4. feat: surface RPC requests for AD decisions at datatracker (ietf-tool…

    …s#11596)
    
    * feat: add model for open RPC action holder entries
    
    The RPC tool sends the action holders it is waiting on with every
    publication queue push, and the datatracker discards them. Add somewhere
    to keep them so an Area Director can be shown when the RPC needs a
    decision from them.
    
    The RPC tool owns these entries; this is a read-only capture held here so
    the datatracker can query them efficiently. Only open entries are kept,
    so readers do not need to filter. The admin registration is read-only for
    the same reason: every push replaces the contents.
    
    * feat: capture open RPC action holders from the queue push
    
    The publication queue push already carries the action holders the RPC is
    waiting on. Reconcile them against the open entry table on each push,
    which is a full snapshot: entries the RPC completed or removed, and
    entries for documents that have left the queue, are dropped.
    
    Never associate an entry with the "(System)" person. The RPC tool sends
    its own placeholder person when no real one was named, and that arrives
    both with and without a body set - its edit path can change the body
    without touching the person - so the person id alone has to be enough to
    reject it.
    
    * feat: show ADs the RPC decisions pending from them
    
    Add a section to the AD document list for the actions the RPC is waiting
    on that AD for. Each row links to the queue site final review page for
    its document, which is where the request is spelled out - unless the RPC
    has not assigned an RFC number yet, in which case there is no such page.
    
    Who holds an action and since when is public. The request text itself is
    shown only to the IESG, the Secretariat, the RPC, and whoever is being
    asked for the decision.
    
    * feat: count pending RPC decisions on the IESG dashboard
    
    Add a table listing each AD the RPC is currently waiting on, above the
    state count tables and linking to that AD's document list. Only ADs with
    something pending get a row, and the table is absent when the RPC is
    waiting on nobody.
    
    It is kept out of the state count tables because it cannot honestly join
    them: those show a 120-day trend, while the open entries the RPC pushes
    are a snapshot with no history to bucket.
    
    * feat: show open RPC action holders on the document page
    
    Add the people the RPC is waiting on to the RFC Editor block, so the
    document itself says who holds the decision and since when.
    
    Only entries naming a person are listed. An action held by a body, or by
    the RPC tool's own placeholder person, is already covered by the queue
    status line in the same block.
    
    * fix: only show rpc action holders on the current draft version
    
    * fix: show action holder request on ad pages
    
    * docs: correct comment gate rationale
    
    * fix: add API resource for open RPC action holder entries
    
    * docs: improve accuracy of comments
    
    * fix: rename/redoc when to display comment method. Address other review nits
    rjsparks authored Aug 20, 2026
    Configuration menu
    Copy the full SHA
    e756948 View commit details
    Browse the repository at this point in the history
  5. Configuration menu
    Copy the full SHA
    bc21ea4 View commit details
    Browse the repository at this point in the history

Commits on Aug 21, 2026

  1. fix: generate idnits2 rfc-status blob for 5-digit RFC numbers (ietf-t…

    …ools#11621)
    
    generate_idnits2_rfc_status() allocated a fixed 10000-element array
    and indexed it by RFC number, so it raised IndexError for any RFC
    above 10000. The task has been failing on every run since 2026-06-16,
    and because ietf/doc/tasks.py computes the blob outside its try block,
    the exception escapes before anything is written. The served file has
    been frozen at 9998 characters since then (content-length 10154),
    stale for all RFCs rather than only 5-digit ones.
    
    This commit sizes the array from the highest rfc_number instead. The
    most recent versions of idnits2 (through 2.17.1) will correctly
    consume this larger array without modification.
    
    It also stops the generator crashing on RFC rows it doesn't expect by
    excluding RFCs with a null rfc_number (int(None) raises TypeError) and
    falling back to 'U' for an unrecognised std_level_id (symbols[None]
    raises KeyError). Document.std_level is nullable, and a single such
    row would take down the whole task.
    
    To allow existing idnits clients at version 2.17.1 and below to keep
    operating, override RFC 16 to 'O'. This deliberately contradicts both
    the datatracker and the RFC Editor, which record RFC 16 as updated
    rather than obsoleted. idnits2 validates its download of this file by
    matching the first 64 characters against a literal pattern asserting
    'O' at position 16. The reason is lost, but it was likely the result
    of manual curation at tools.ietf.org long ago. Without the override,
    existing idnits2 clients discard the file as corrupt, fall back to
    whatever stale copy they have, and silently perform no RFC status
    checks at all. This is independent of the crash and predates it.
    
    Note that the generator uses a floor of 6312. This is required because
    the RFC 16, RFC 200 and RFC 6312 workarounds write those offsets
    unconditionally, so the array must reach 6312 regardless of the data;
    without the floor the generator raises IndexError for any dataset
    whose highest RFC is below that. It also keeps output identical to the
    previous behaviour, where the fixed 10000-element array always had
    those offsets in range. Making the workaround writes conditional
    instead would remove the need for the floor, but that was not done
    here.
    
    Verification:
    
    - Against the production snapshot, positions 1..9993 and the first line
      are byte-identical to the pre-change algorithm; the blob extends from
      9999 to 10031. rfc10001='B', rfc10008='P', rfc10031='P' match their
      std_level_id values.
    - idnits2's own download validation (grep -qsE against the first line)
      now passes, where it fails against the file production serves today.
    - idnits2's lookup path resolves 5-digit statuses correctly against the
      generated file: rfc10001 -> Best Current Practice, rfc10031 ->
      Proposed Standard, rfc10032 -> past end of blob.
    - ietf.doc.tests (122 tests) and ietf.doc.tests_tasks
      ietf.doc.tests_downref (15 tests) pass.
    
    This commit produced primarily by Claude.
    rjsparks authored Aug 21, 2026
    Configuration menu
    Copy the full SHA
    5a88e9e View commit details
    Browse the repository at this point in the history
Loading