Skip to content

refactor(lark): decide the application id shape in one owner - #5878

Open
Hsuehtan wants to merge 2 commits into
loopx-project:mainfrom
Hsuehtan:refactor/lark-app-id-shape-owner
Open

Hsuehtan wants to merge 2 commits into
loopx-project:mainfrom
Hsuehtan:refactor/lark-app-id-shape-owner

Conversation

@Hsuehtan

@Hsuehtan Hsuehtan commented Oct 7, 2026 •

Copy link
Copy Markdown

Goal And Delivered Outcome

Author Declaration

  • Written by: model_agent (Claude, Anthropic), against this repository's main at aa87cc019.

Implemented against

  • Specification and revision: the owner module's own contract (identity_shapes.py:1-16): "Searching
    for an identifier inside larger text is the same decision about a different question, so it is stated
    here too and nowhere else … both spellings stay distinct and one module decides both", plus the
    guard's three questions (second definition / consumer wiring / anchored-vs-search separation).
Criterion (spec clause) Disposition Symbol / path Test or command
one module decides each identifier body implemented identity_shapes.LARK_APP_ID_PATTERN test_no_module_restates_a_lark_identifier_shape
both spellings stated, and kept apart implemented — app id has only the whole-value spelling, because no site searches for it ANCHORED_EXPORTS["app_id"], SEARCH_IDENTIFIERS unchanged test_owner_states_both_spellings_and_nothing_else
consumers hold the owner's object implemented 8 hub callers + bot_scopes + the delivery contract test_every_app_id_caller_holds_the_owners_object, test_the_delivery_contract_holds_the_owners_object_too
a converted declared site must retire its declaration implemented DECLARED_INDIVIDUAL_SITES count 1 → 2 test_a_converted_declared_site_is_not_silently_reintroduced
the scan sees the spellings a future edit will use implemented two new cli_ probe rows test_the_scan_reports_a_restated_shape
the unfoldable layer stays signal, not noise implemented IDENTIFIER_RELEVANCE_TOKENS gated on app_id, not on cli_ test_no_lark_module_hides_an_unfoldable_identifier_construction
  • Self-check before submission: measured the relevance-gate choice instead of guessing it — keying on
    cli_ pulled a setup-URL pattern and a data-built markdown heading into the unfoldable layer, so the
    gate uses the field name; the first draft's consumer assertion (that an alias import should not appear
    as a module-level binding) was wrong and was replaced by the object-identity proof the sibling hub test
    already uses. Left out on purpose: SAFE_PROFILE_PATTERN, which the transport hub still compiles and
    which two Lark surfaces share — a different decision, named under Scope.

Scope And Continuation

  • Completed scope and remaining work:
    • Done: three of the four compiles deleted, the shape exported from the owner under
      ANCHORED_EXPORTS, the hub's re-export switched to the same alias-import form its other three
      re-exports already use, the delivery contract's anchored duplicate folded into the owner's single
      spelling, and the census/guard extended (bodies, exports, probes, consumers, declaration budget).
    • loopx/extensions/lark/event_collector_runtime.py declared, not converted: feat(goal-channel): compose scoped claims and private reconnect context (#5198) #5248 is
      restructuring that file, so its cli_ compile is added to its existing declaration with the count
      going 1 → 2 and the reason written next to it. Converting it deletes the entry, and the staleness
      test fails if someone converts it and leaves the entry (mutation N7).
    • Deliberately not merged: chat_action_normalization's principal rule
      ^[a-z][a-z0-9._-]{0,30}:<opaque>$ embeds an opaque body behind a required family prefix — a
      different question, which is why it is not in the census's bodies and why converting it here would
      have been a silent narrowing. Three further rules share the same {1,200} bound
      (loopx/chat_endpoints.py, loopx/chat_store.py, multi_subagent/native_child_receipts.py) with
      different character classes or starts, and stay separate under the registry's rule that a shared
      name with different values is not drift.
  • Slice boundary / successor: independently reversible — reverting restores four files and one guard
    entry without touching the owner's other four shapes. Successor: SAFE_PROFILE_PATTERN, compiled in
    the transport hub and again in document_comment_provider.py; and converting the declared
    event_collector_runtime site once feat(goal-channel): compose scoped claims and private reconnect context (#5198) #5248 lands.

Validation

  • Tested revision: 3ebb47000 (2 commits, 5 files, +118 −18)
  • Run state: finished
  • Input classes: public_fixture, synthetic
Check kind Result Public-safe evidence / limitation
unit passed python -m pytest -q tests/architecture/test_lark_identity_shape_owner.py -> 84 passed; the same file collects 62 at the base revision, so the +22 cases are the new consumer, equivalence and probe rows.
unit passed python -m pytest -q tests/extensions -k lark -> 788 passed / 0 failed, 623 deselected: the Lark provider, transport, inbox, setup, targets and delivery surfaces that read the gathered shape.
integration passed (net zero) python -m pytest -q tests/architecture tests/canary — head 2 failed / 1466 passed, unmodified base worktree at the same revision's parent 2 failed / 1444 passed, failure ids identical (test_top_level_module_budget… = the 148-vs-147 pin reported in #5685, test_source_session_registry_denial…). Same interpreter, same qualified Node line, both runs in one window.
static passed python -m ruff check loopx/extensions/lark tests/architecture/test_lark_identity_shape_owner.py clean; python -m mypy -> Success: no issues found in 19 source files; loopx check --scan-path loopx/extensions/lark --scan-path tests/architecture/test_lark_identity_shape_owner.py -> errors=0.
census passed (net zero) python examples/semantic-vocabulary-drift-smoke.py measured on this head and on an unmodified worktree at the base revision, byte-for-byte the same line: same_runtime_forks=2/2 same_runtime_fork_definitions=5/5 conflicting_values=16/16 conflicting_definitions=54/54 schema_version_same_runtime_forks=0/0 multi_value_twins=8/8 multi_value_forks=2/2 multi_value_forks_semantic=1/1 multi_value_fork_definitions=6/6 same_runtime_forks_semantic=2/2 conflicting_values_semantic=0/0, twins_raw=45, generated_verified=2, independently_maintained=43/43. No registry budget and no BUDGET_ANCHOR literal moves in this PR, and the registry I/O census test inside the compared architecture selection reports the same outcome on both sides.
regression_parity passed Six mutations, five killed: a converted site recompiling the body (4 red, incl. the census and the consumer row), the owner's body narrowed (2), the delivery contract restating its anchored copy (4), the declared site converted without retiring its declaration (2), and the owner dropping its trailing anchor (2). The sixth — removing the hub's alias import so it re-compiles — surfaces as 1 collection error rather than a named assertion, because eight modules import that name and fail to bind it; reported as-is. The last row is the equivalence evidence in mutation form: dropping the anchor fails only the two registration asserts and no behavioural case, which is what "every site applies fullmatch" predicts. ruff format --check is not a gate here; the guard file already reports 12 hunks at base and 12 at head, and the four product files report 0 both sides.
  • Coverage and gaps: covered because the census decides on the folded value, so re.compile(X), an
    inline re.fullmatch and a two-literal concatenation are all offenders — two of the three converted
    sites were written exactly that way, and the probe rows now include both cli_ spellings. Gaps named
    plainly: (a) event_collector_runtime.py is declared, not converted, so the package still holds a
    second compile of this body until feat(goal-channel): compose scoped claims and private reconnect context (#5198) #5248 lands; (b) the unfoldable layer keys on app_id, so a module
    that builds this body from data without naming an app_id field would be reported as foldable — the
    declared-layer comment states that trade-off; (c) the TS side is untouched, and the Lark app id has no
    TypeScript counterpart in this package, so no twin budget moves.

See validation disclosure guidance.

Frontend / Visual Evidence

  • UI impact: none
  • Before: N/A
  • After: N/A
  • States and viewports shown: N/A
  • Source data: none
  • Attention review: N/A

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring (no functional changes) — every site already applied fullmatch, so the anchors are
    redundant; the equivalence is asserted over boundary values rather than claimed
  • Documentation update
  • Test update

LoopX Area

  • Host or runtime integration (the Lark/Feishu goal-channel and bot surfaces)

Technical Direction

Shared-authority RFC fixture impact

N/A — no TypeScript control-plane migration or shared Goal Authority claim. No .ts file, no
conformance fixture and no dual-runtime twin budget is touched by this diff.

Four sites compiled the cli_-prefixed application id themselves -- the transport
hub, bot_scopes, event_collector_runtime and goal_channel_delivery_contract, the
last with its own anchors on the same body -- and eight more modules import the
transport hub's name, so a bound fix had three possible homes. The shape now
lives in identity_shapes.LARK_APP_ID_PATTERN, which already owns the other four
Lark identifier bodies and states why anchored and unanchored spellings stay
distinct.

Every caller applies fullmatch, where the anchors are redundant, so no product
answer changes; the guard's tricky-value table pins that. event_collector_runtime
is declared by file and count instead of converted, because loopx-project#5248 restructures
that file.

Signed-off-by: Hsuehtan <296098438+Hsuehtan@users.noreply.github.com>
Three couplings showed up when the shape was actually run, not assumed:

- The unfoldable layer is gated on identifier field names. Keying it on the
  cli_ prefix instead dragged in a setup-URL pattern and a markdown heading
  built from data, exactly the noise the layer's comment warns about, so the
  token is the field name app_id.
- An alias import does create a module-level binding, so the consumer assertion
  that rejected one was wrong; object identity is the wiring proof.
- The declared-site fixture in the staleness test carried the old budget of one
  construction; with the declared file now holding two, it has to state both.

Signed-off-by: Hsuehtan <296098438+Hsuehtan@users.noreply.github.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant