Skip to content

chore(hogli): validate canonical facade alternation in tach.toml#56699

Merged
webjunkie merged 9 commits intomasterfrom
claude/validate-product-lint-tach-mrtn3
May 6, 2026
Merged

chore(hogli): validate canonical facade alternation in tach.toml#56699
webjunkie merged 9 commits intomasterfrom
claude/validate-product-lint-tach-mrtn3

Conversation

@webjunkie
Copy link
Copy Markdown
Contributor

Problem

As the product architecture evolves toward isolated products with facade contracts, we need to ensure consistency in how these facades are exposed globally. Currently, there's no validation that:

  1. All isolated products (those with backend/facade/contracts.py) are listed in the canonical facade alternation block
  2. All products listed in the canonical alternation actually exist and are isolated
  3. The alternation patterns are correctly formed

This can lead to stale entries or missing facades that aren't reachable from outside the product.

Changes

Added comprehensive validation for the canonical [[interfaces]] alternation block in tach.toml:

New functions in checks.py:

  • _iter_interface_blocks() — Helper to parse all [[interfaces]] blocks from tach.toml
  • _pattern_targets_public_surface() — Check if a pattern targets backend.facade or backend.presentation
  • _is_canonical_facade_expose() — Identify canonical blocks (those exposing only public surface)
  • _names_from_pattern() — Extract product names from tach patterns (handles products.name and products.(a|b|c) forms)
  • validate_facade_alternation() — Main validation function that enforces three rules:
    1. Every product in the alternation must exist and be isolated
    2. Every isolated product must appear in some canonical alternation block
    3. All patterns must be parseable

Integration in lint.py:

  • Added _lint_facade_alternation() to run the global check during lint_all_products()
  • Updated output to show facade alternation validation results alongside per-product checks
  • Integrated with GitHub annotations for CI visibility

Refactoring in checks.py:

  • Simplified has_legacy_interface_leaks() to use the new helper functions, reducing duplication and improving maintainability

How did you test this code?

Added comprehensive unit tests in test_checks.py:

  • TestValidateFacadeAlternation — 9 test cases covering:
    • Empty tach.toml (no issues)
    • Missing canonical block (no issues, per-product checks handle it)
    • Clean alternation with all products isolated and listed
    • Stale entries (product missing or not isolated)
    • Missing entries (isolated product not in alternation)
    • Legacy blocks don't count as canonical
    • Both single and double backslash forms parse correctly
    • Non-isolated products are ignored
  • TestNamesFromPattern — 12 parametrized tests covering pattern extraction for various forms

All tests pass and validate the three core rules.

Publish to changelog?

No — this is internal tooling for product architecture validation.

https://claude.ai/code/session_01HPswQQ5v1x2MT16pcdSy2K

Copilot AI review requested due to automatic review settings April 28, 2026 11:34
@assign-reviewers-posthog assign-reviewers-posthog Bot requested a review from a team April 28, 2026 11:34
@webjunkie webjunkie changed the title Add global facade alternation validation for isolated products chore(hogli): validate canonical facade alternation in tach.toml Apr 28, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 28, 2026

Prompt To Fix All With AI
This is a comment left during a code review.
Path: common/hogli/product/checks.py
Line: 71

Comment:
**Backslash form not normalised in `from_patterns` comparison**

`from_patterns` contains raw TOML strings extracted by `re.findall(r'"(.*?)"', ...)`, so if any per-product legacy-leak block uses the escaped form `"products\\.experiments"` the extracted string will be `products\\.experiments`, which will never equal the plain `module_path` string `products.experiments`. The block would be silently skipped, causing `has_legacy_interface_leaks` to return `False` when it should return `True`.

`_pattern_targets_public_surface` correctly calls `.replace("\\", "")` before comparing — the same normalisation is needed here:

```python
if from_patterns != [module_path]:
```

should be

```python
normalized_from = [p.replace("\\", "") for p in from_patterns]
if normalized_from != [module_path]:
```

```suggestion
        normalized_from = [p.replace("\\", "") for p in from_patterns]
        if normalized_from != [module_path]:
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: common/hogli/tests/test_checks.py
Line: 582-705

Comment:
**`TestValidateFacadeAlternation` is not parametrised**

The repo rule is "we always prefer parametrised tests." The nine methods in `TestValidateFacadeAlternation` share the same shape — build a filesystem with `_mkproduct`, feed a tach string to `validate_facade_alternation`, and assert on the returned issues. They could be expressed as a single `@pytest.mark.parametrize` table where each row carries the products to create (name, isolated flag) and the TOML string, greatly reducing boilerplate and making it easier to add cases. `TestNamesFromPattern` in the same PR is already parametrised and shows the pattern works well here too.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "refactor(hogli): share interface-block p..." | Re-trigger Greptile

Comment thread common/hogli/product/checks.py Outdated
Comment thread common/hogli/tests/test_checks.py
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 89638b6b3b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +160 to +163
if not is_isolated_product(product_dir / "backend"):
issues.append(
f"canonical facade alternation lists '{name}' but products/{name}/backend/facade/contracts.py "
"is missing — either add contracts.py or remove the entry from tach.toml"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid blocking lint on pre-existing canonical entries

This new isolation gate is now a hard error, but the current repository state already violates it: tach.toml's canonical alternation still includes platform_features while products/platform_features/backend/facade/contracts.py is absent, so this branch will always emit an issue here and then fail product:lint --all (which is run in repo checks at .github/workflows/ci-backend.yml, line 497). That makes backend CI fail for unrelated PRs immediately after this commit; the change should either update tach.toml in the same commit or keep these findings non-blocking until existing entries are reconciled.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new global Hogli lint that validates the canonical [[interfaces]] facade alternation in tach.toml, ensuring isolated products are correctly and consistently exposed via their public surface.

Changes:

  • Introduces validate_facade_alternation() and supporting helpers to parse/validate canonical [[interfaces]] blocks and product coverage.
  • Integrates the new validation into lint_all_products() with GitHub Actions annotations.
  • Adds unit tests for alternation validation and from-pattern name extraction.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
common/hogli/product/checks.py Adds helpers to parse [[interfaces]] blocks, classify canonical public-surface exposes, extract product names from from patterns, and validate alternation completeness/staleness.
common/hogli/product/lint.py Runs the new global tach.toml alternation validation once per --all invocation and surfaces results (incl. GH annotations).
common/hogli/tests/test_checks.py Adds coverage for alternation validation scenarios and _names_from_pattern() parsing behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread common/hogli/tests/test_checks.py Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 28, 2026

Size Change: 0 B

Total Size: 133 MB

ℹ️ View Unchanged
Filename Size Change
frontend/dist/368Hedgehogs 5.3 kB 0 B
frontend/dist/abap 14.2 kB 0 B
frontend/dist/AccountSocialConnected 2.23 kB 0 B
frontend/dist/Action 23.9 kB 0 B
frontend/dist/Actions 1.06 kB 0 B
frontend/dist/AdvancedActivityLogsScene 37 kB 0 B
frontend/dist/AgenticAuthorize 5.49 kB 0 B
frontend/dist/apex 3.99 kB 0 B
frontend/dist/ApprovalDetail 16.3 kB 0 B
frontend/dist/array.full.es5.js 344 kB 0 B
frontend/dist/array.full.js 437 kB 0 B
frontend/dist/array.js 189 kB 0 B
frontend/dist/AsyncMigrations 13.2 kB 0 B
frontend/dist/AuthorizationStatus 755 B 0 B
frontend/dist/azcli 885 B 0 B
frontend/dist/bat 1.88 kB 0 B
frontend/dist/BatchExportScene 60.5 kB 0 B
frontend/dist/bicep 2.59 kB 0 B
frontend/dist/Billing 527 B 0 B
frontend/dist/BillingSection 20.8 kB 0 B
frontend/dist/BoxPlot 5.08 kB 0 B
frontend/dist/browserAll-0QZMN1W2 37.4 kB 0 B
frontend/dist/ButtonPrimitives 596 B 0 B
frontend/dist/CalendarHeatMap 4.83 kB 0 B
frontend/dist/cameligo 2.23 kB 0 B
frontend/dist/changeRequestsLogic 578 B 0 B
frontend/dist/CLIAuthorize 11.4 kB 0 B
frontend/dist/CLILive 4.05 kB 0 B
frontend/dist/clojure 9.68 kB 0 B
frontend/dist/coffee 3.63 kB 0 B
frontend/dist/Cohort 24.8 kB 0 B
frontend/dist/CohortCalculationHistory 6.26 kB 0 B
frontend/dist/Cohorts 9.43 kB 0 B
frontend/dist/ConfirmOrganization 4.56 kB 0 B
frontend/dist/conversations.js 67.2 kB 0 B
frontend/dist/Coupons 759 B 0 B
frontend/dist/cpp 5.33 kB 0 B
frontend/dist/Create 868 B +174 B (+25.07%) 🚨
frontend/dist/crisp-chat-integration.js 1.88 kB 0 B
frontend/dist/csharp 4.56 kB 0 B
frontend/dist/csp 1.45 kB 0 B
frontend/dist/css 4.54 kB 0 B
frontend/dist/cssMode 4.2 kB 0 B
frontend/dist/CustomCssScene 3.59 kB 0 B
frontend/dist/CustomerAnalyticsConfigurationScene 2.1 kB 0 B
frontend/dist/CustomerAnalyticsScene 26.6 kB 0 B
frontend/dist/CustomerJourneyBuilderScene 1.87 kB 0 B
frontend/dist/CustomerJourneyTemplatesScene 7.54 kB 0 B
frontend/dist/customizations.full.js 17.9 kB 0 B
frontend/dist/CyclotronJobInputAssignee 1.36 kB 0 B
frontend/dist/CyclotronJobInputBusinessHours 2.75 kB 0 B
frontend/dist/CyclotronJobInputTicketTags 750 B 0 B
frontend/dist/cypher 3.42 kB 0 B
frontend/dist/dart 4.29 kB 0 B
frontend/dist/Dashboard 1.17 kB 0 B
frontend/dist/Dashboards 22 kB 0 B
frontend/dist/DashboardTemplateCopyScene 5.74 kB 0 B
frontend/dist/DataManagementScene 680 B 0 B
frontend/dist/DataPipelinesNewScene 2.37 kB 0 B
frontend/dist/DataWarehouseScene 1.28 kB -55 B (-4.12%)
frontend/dist/Deactivated 1.16 kB 0 B
frontend/dist/dead-clicks-autocapture.js 13.1 kB 0 B
frontend/dist/DeadLetterQueue 5.42 kB 0 B
frontend/dist/DebugScene 20.1 kB 0 B
frontend/dist/decompressionWorker 2.85 kB 0 B
frontend/dist/decompressionWorker.js 2.85 kB 0 B
frontend/dist/DefinitionEdit 8.61 kB 0 B
frontend/dist/DefinitionView 23.9 kB 0 B
frontend/dist/DestinationsScene 2.75 kB 0 B
frontend/dist/dist 609 B 0 B
frontend/dist/dockerfile 1.91 kB 0 B
frontend/dist/EarlyAccessFeature 787 B 0 B
frontend/dist/EarlyAccessFeatures 2.88 kB 0 B
frontend/dist/ecl 5.38 kB 0 B
frontend/dist/EditorScene 935 B 0 B
frontend/dist/elixir 10.3 kB 0 B
frontend/dist/elk.bundled 1.44 MB 0 B
frontend/dist/EmailMFAVerify 3.05 kB 0 B
frontend/dist/EndpointScene 39 kB 0 B
frontend/dist/EndpointsScene 21.4 kB 0 B
frontend/dist/ErrorTrackingIssueFingerprintsScene 7.02 kB 0 B
frontend/dist/ErrorTrackingIssueScene 99.2 kB 0 B
frontend/dist/ErrorTrackingScene 22.6 kB 0 B
frontend/dist/EvaluationTemplates 609 B 0 B
frontend/dist/EventsScene 2.6 kB 0 B
frontend/dist/exception-autocapture.js 11.8 kB 0 B
frontend/dist/Experiment 193 kB 0 B
frontend/dist/Experiments 18.2 kB 0 B
frontend/dist/exporter 21.4 MB 0 B
frontend/dist/exporter.js 21.4 MB 0 B
frontend/dist/ExportsScene 4.02 kB 0 B
frontend/dist/FeatureFlag 129 kB 0 B
frontend/dist/FeatureFlags 640 B 0 B
frontend/dist/FeatureFlagTemplatesScene 7.07 kB 0 B
frontend/dist/FlappyHog 5.82 kB 0 B
frontend/dist/flow9 1.85 kB 0 B
frontend/dist/freemarker2 16.7 kB 0 B
frontend/dist/fsharp 3.02 kB 0 B
frontend/dist/go 2.69 kB 0 B
frontend/dist/graphql 2.3 kB 0 B
frontend/dist/Group 14.5 kB 0 B
frontend/dist/Groups 3.94 kB 0 B
frontend/dist/GroupsNew 7.38 kB 0 B
frontend/dist/handlebars 7.38 kB 0 B
frontend/dist/hcl 3.63 kB 0 B
frontend/dist/HealthCategoryDetailScene 7.27 kB 0 B
frontend/dist/HealthScene 10.6 kB 0 B
frontend/dist/HeatmapNewScene 4.65 kB 0 B
frontend/dist/HeatmapRecordingScene 4.04 kB 0 B
frontend/dist/HeatmapScene 6.66 kB 0 B
frontend/dist/HeatmapsScene 3.92 kB 0 B
frontend/dist/hls 394 kB 0 B
frontend/dist/HogFunctionScene 59.3 kB 0 B
frontend/dist/HogRepl 7.4 kB 0 B
frontend/dist/html 5.62 kB 0 B
frontend/dist/htmlMode 4.65 kB 0 B
frontend/dist/image-blob-reduce.esm 49.5 kB 0 B
frontend/dist/InboxScene 59.8 kB 0 B
frontend/dist/index 307 kB 0 B
frontend/dist/index.js 307 kB 0 B
frontend/dist/ini 1.14 kB 0 B
frontend/dist/InsightQuickStart 5.46 kB 0 B
frontend/dist/InsightScene 28.8 kB 0 B
frontend/dist/IntegrationsRedirect 772 B 0 B
frontend/dist/intercom-integration.js 1.93 kB 0 B
frontend/dist/InviteSignup 14.4 kB 0 B
frontend/dist/java 3.26 kB 0 B
frontend/dist/javascript 1.02 kB 0 B
frontend/dist/jsonMode 13.9 kB 0 B
frontend/dist/julia 7.26 kB 0 B
frontend/dist/kotlin 3.44 kB 0 B
frontend/dist/lazy 159 kB 0 B
frontend/dist/LegacyPluginScene 20.7 kB 0 B
frontend/dist/LegalDocumentNewScene 59.4 kB 0 B
frontend/dist/LegalDocumentsScene 4.67 kB 0 B
frontend/dist/LemonTextAreaMarkdown 536 B 0 B
frontend/dist/less 3.93 kB 0 B
frontend/dist/lexon 2.47 kB 0 B
frontend/dist/lib 2.25 kB 0 B
frontend/dist/Link 502 B 0 B
frontend/dist/LinkScene 24.9 kB 0 B
frontend/dist/LinksScene 4.23 kB 0 B
frontend/dist/liquid 4.57 kB 0 B
frontend/dist/LiveDebugger 19.2 kB 0 B
frontend/dist/LiveEventsTable 5.26 kB 0 B
frontend/dist/LLMAnalyticsClusterScene 18.8 kB 0 B
frontend/dist/LLMAnalyticsClustersScene 51.8 kB 0 B
frontend/dist/LLMAnalyticsDatasetScene 19.7 kB 0 B
frontend/dist/LLMAnalyticsDatasetsScene 3.32 kB 0 B
frontend/dist/LLMAnalyticsEvaluation 58.8 kB 0 B
frontend/dist/LLMAnalyticsEvaluationsScene 29.9 kB 0 B
frontend/dist/LLMAnalyticsPlaygroundScene 36.8 kB 0 B
frontend/dist/LLMAnalyticsScene 118 kB 0 B
frontend/dist/LLMAnalyticsSessionScene 13.4 kB 0 B
frontend/dist/LLMAnalyticsTraceScene 129 kB 0 B
frontend/dist/LLMAnalyticsUsers 560 B 0 B
frontend/dist/LLMASessionFeedbackDisplay 4.87 kB 0 B
frontend/dist/LLMPromptScene 17.5 kB 0 B
frontend/dist/LLMPromptsScene 4.51 kB 0 B
frontend/dist/LLMSkillScene 623 B 0 B
frontend/dist/LLMSkillsScene 640 B 0 B
frontend/dist/Login 8.65 kB 0 B
frontend/dist/Login2FA 4.28 kB 0 B
frontend/dist/logs.js 38.5 kB 0 B
frontend/dist/LogsAlertDetailScene 15.6 kB 0 B
frontend/dist/LogsAlertNewScene 3.76 kB 0 B
frontend/dist/LogsScene 11.4 kB 0 B
frontend/dist/lua 2.16 kB 0 B
frontend/dist/m3 2.85 kB 0 B
frontend/dist/main 819 kB 0 B
frontend/dist/ManagedMigration 14.2 kB 0 B
frontend/dist/markdown 3.83 kB 0 B
frontend/dist/MarketingAnalyticsScene 39.8 kB 0 B
frontend/dist/MaterializedColumns 10.2 kB 0 B
frontend/dist/Max 835 B 0 B
frontend/dist/mdx 5.43 kB 0 B
frontend/dist/memlens.lib.bundle 27.9 kB 0 B
frontend/dist/MessageTemplate 16.3 kB 0 B
frontend/dist/MetricsScene 872 B 0 B
frontend/dist/mips 2.62 kB 0 B
frontend/dist/ModelsScene 13.7 kB 0 B
frontend/dist/MonacoDiffEditor 437 B 0 B
frontend/dist/monacoEditorWorker 288 kB 0 B
frontend/dist/monacoEditorWorker.js 288 kB 0 B
frontend/dist/monacoJsonWorker 419 kB 0 B
frontend/dist/monacoJsonWorker.js 419 kB 0 B
frontend/dist/monacoTsWorker 7.02 MB 0 B
frontend/dist/monacoTsWorker.js 7.02 MB 0 B
frontend/dist/MoveToPostHogCloud 4.49 kB 0 B
frontend/dist/msdax 4.95 kB 0 B
frontend/dist/mysql 11.3 kB 0 B
frontend/dist/NavTabChat 4.72 kB 0 B
frontend/dist/NewSourceScene 817 B 0 B
frontend/dist/NewTabScene 681 B 0 B
frontend/dist/NodeDetailScene 16.4 kB 0 B
frontend/dist/NotebookCanvasScene 3.27 kB 0 B
frontend/dist/NotebookPanel 5.24 kB 0 B
frontend/dist/NotebookScene 8.28 kB 0 B
frontend/dist/NotebooksScene 7.62 kB 0 B
frontend/dist/OAuthAuthorize 607 B 0 B
frontend/dist/objective-c 2.44 kB 0 B
frontend/dist/Onboarding 734 kB 0 B
frontend/dist/OnboardingCouponRedemption 1.23 kB 0 B
frontend/dist/pascal 3.03 kB 0 B
frontend/dist/pascaligo 2.04 kB 0 B
frontend/dist/passkeyLogic 518 B 0 B
frontend/dist/PasswordReset 4.39 kB 0 B
frontend/dist/PasswordResetComplete 3.02 kB 0 B
frontend/dist/PendingDeletion 2.24 kB 0 B
frontend/dist/perl 8.29 kB 0 B
frontend/dist/PersonScene 17.7 kB 0 B
frontend/dist/PersonsScene 4.72 kB 0 B
frontend/dist/pgsql 13.5 kB 0 B
frontend/dist/php 8.06 kB 0 B
frontend/dist/PipelineStatusScene 9.14 kB 0 B
frontend/dist/pla 1.72 kB 0 B
frontend/dist/posthog 145 kB 0 B
frontend/dist/postiats 7.9 kB 0 B
frontend/dist/powerquery 17 kB 0 B
frontend/dist/powershell 3.31 kB 0 B
frontend/dist/PreflightCheck 5.6 kB 0 B
frontend/dist/product-tours.js 115 kB 0 B
frontend/dist/ProductTour 274 kB 0 B
frontend/dist/ProductTours 4.72 kB 0 B
frontend/dist/ProjectHomepage 40.9 kB 0 B
frontend/dist/protobuf 9.09 kB 0 B
frontend/dist/pug 4.86 kB 0 B
frontend/dist/python 4.8 kB 0 B
frontend/dist/qsharp 3.23 kB 0 B
frontend/dist/QueryPerformance 7.03 kB 0 B
frontend/dist/r 3.16 kB 0 B
frontend/dist/razor 9.38 kB 0 B
frontend/dist/react-json-view 121 kB 0 B
frontend/dist/recorder-v2.js 111 kB 0 B
frontend/dist/recorder.js 111 kB 0 B
frontend/dist/redis 3.59 kB 0 B
frontend/dist/redshift 11.8 kB 0 B
frontend/dist/RegionMap 29.5 kB 0 B
frontend/dist/render-query 21.1 MB 0 B
frontend/dist/render-query.js 21.1 MB 0 B
frontend/dist/ResourceTransfer 9.21 kB 0 B
frontend/dist/restructuredtext 3.94 kB 0 B
frontend/dist/RevenueAnalyticsScene 25.6 kB 0 B
frontend/dist/ruby 8.54 kB 0 B
frontend/dist/rust 4.2 kB 0 B
frontend/dist/SavedInsights 698 B 0 B
frontend/dist/sb 1.86 kB 0 B
frontend/dist/scala 7.36 kB 0 B
frontend/dist/schema 693 kB 0 B
frontend/dist/scheme 1.8 kB 0 B
frontend/dist/scss 6.45 kB 0 B
frontend/dist/SdkDoctorScene 9.45 kB 0 B
frontend/dist/SessionAttributionExplorerScene 6.66 kB 0 B
frontend/dist/SessionGroupSummariesTable 4.66 kB 0 B
frontend/dist/SessionGroupSummaryScene 17 kB 0 B
frontend/dist/SessionProfileScene 15.1 kB 0 B
frontend/dist/SessionRecordingDetail 1.79 kB 0 B
frontend/dist/SessionRecordingFilePlaybackScene 4.5 kB 0 B
frontend/dist/SessionRecordings 776 B 0 B
frontend/dist/SessionRecordingsKiosk 8.88 kB 0 B
frontend/dist/SessionRecordingsPlaylistScene 4.18 kB 0 B
frontend/dist/SessionRecordingsSettingsScene 1.93 kB 0 B
frontend/dist/SessionsScene 4.01 kB 0 B
frontend/dist/SettingsScene 3.02 kB 0 B
frontend/dist/SharedMetric 4.97 kB 0 B
frontend/dist/SharedMetrics 583 B 0 B
frontend/dist/shell 3.11 kB 0 B
frontend/dist/SignupContainer 25.9 kB 0 B
frontend/dist/Site 1.22 kB 0 B
frontend/dist/solidity 18.6 kB 0 B
frontend/dist/sophia 2.8 kB 0 B
frontend/dist/SourceScene 792 B 0 B
frontend/dist/SourcesScene 6.13 kB 0 B
frontend/dist/sparql 2.59 kB 0 B
frontend/dist/sql 10.3 kB 0 B
frontend/dist/SqlVariableEditScene 7.28 kB 0 B
frontend/dist/st 7.44 kB 0 B
frontend/dist/StartupProgram 21.2 kB 0 B
frontend/dist/StripeConfirmInstall 3.57 kB 0 B
frontend/dist/SubscriptionScene 13.3 kB 0 B
frontend/dist/SubscriptionsScene 4.94 kB 0 B
frontend/dist/SupportSettingsScene 1.2 kB 0 B
frontend/dist/SupportTicketScene 24.6 kB 0 B
frontend/dist/SupportTicketsScene 767 B 0 B
frontend/dist/Survey 882 B 0 B
frontend/dist/SurveyFormBuilder 1.57 kB 0 B
frontend/dist/Surveys 18.3 kB 0 B
frontend/dist/surveys.js 94.3 kB 0 B
frontend/dist/SurveyWizard 70.3 kB 0 B
frontend/dist/swift 5.3 kB 0 B
frontend/dist/SystemStatus 16.9 kB 0 B
frontend/dist/systemverilog 7.65 kB 0 B
frontend/dist/TaskDetailScene 22.4 kB 0 B
frontend/dist/TaskTracker 13.6 kB 0 B
frontend/dist/tcl 3.61 kB 0 B
frontend/dist/TextCardMarkdownEditor 11 kB 0 B
frontend/dist/toolbar 11 MB 0 B
frontend/dist/toolbar.js 11 MB 0 B
frontend/dist/ToolbarLaunch 2.55 kB 0 B
frontend/dist/tracing-headers.js 1.74 kB 0 B
frontend/dist/TracingScene 31.4 kB 0 B
frontend/dist/TransformationsScene 1.99 kB 0 B
frontend/dist/TrendsLineChart 34.9 kB 0 B
frontend/dist/tsMode 24 kB 0 B
frontend/dist/twig 6.01 kB 0 B
frontend/dist/TwoFactorReset 4.06 kB 0 B
frontend/dist/typescript 274 B 0 B
frontend/dist/typespec 2.86 kB 0 B
frontend/dist/Unsubscribe 1.69 kB 0 B
frontend/dist/UserInterview 4.57 kB 0 B
frontend/dist/UserInterviews 2.05 kB 0 B
frontend/dist/vb 5.83 kB 0 B
frontend/dist/VercelConnect 5.02 kB 0 B
frontend/dist/VercelLinkError 2.3 kB 0 B
frontend/dist/VerifyEmail 4.81 kB 0 B
frontend/dist/vimMode 211 kB 0 B
frontend/dist/VisualReviewRunScene 42 kB 0 B
frontend/dist/VisualReviewRunsScene 6.59 kB 0 B
frontend/dist/VisualReviewSettingsScene 10.8 kB 0 B
frontend/dist/web-vitals.js 6.39 kB 0 B
frontend/dist/WebAnalyticsScene 5.8 kB 0 B
frontend/dist/WebGLRenderer-DYjOwNoG 60.4 kB 0 B
frontend/dist/WebGPURenderer-B_wkl_Ja 36.3 kB 0 B
frontend/dist/WebScriptsScene 2.61 kB 0 B
frontend/dist/webworkerAll-puPV1rBA 363 B 0 B
frontend/dist/wgsl 7.38 kB 0 B
frontend/dist/Wizard 4.49 kB 0 B
frontend/dist/WorkflowScene 102 kB 0 B
frontend/dist/WorkflowsScene 58.3 kB 0 B
frontend/dist/WorldMap 4.8 kB 0 B
frontend/dist/xml 3.02 kB 0 B
frontend/dist/yaml 4.64 kB 0 B

compressed-size-action

@webjunkie webjunkie marked this pull request as draft April 29, 2026 13:21
claude and others added 8 commits May 4, 2026 12:43
`hogli product:lint --all` now flags stale and missing entries in the
canonical `[[interfaces]]` block (`backend.facade.* + presentation.views.*`):

1. names listed but `products/<name>/` does not exist
2. names listed but `backend/facade/contracts.py` is missing
3. products with `backend/facade/contracts.py` not listed in the alternation

Per-product `TachCheck` already covered (3) via substring search but did
not catch (1) or (2), so stale alternation members were never surfaced.

This commit reports two real gaps in the current tach.toml (platform_features
listed without contracts.py; legal_documents isolated but absent from the
alternation) without auto-fixing them.
…tion checks

`has_legacy_interface_leaks` and `validate_facade_alternation` were both
iterating `[[interfaces]]` blocks and re-implementing the
"expose pattern targets backend.facade or backend.presentation" check —
with divergent backslash semantics (the old `startswith("backend\\.facade")`
literal happened to work only because the on-disk two-backslash form never
matched, and legacy blocks have no facade exposes anyway).

Both now go through `_iter_interface_blocks` for parsing and
`_pattern_targets_public_surface` for the public-surface check. The new
helper normalizes backslashes so it's correct for both the on-disk form
(`\\.`) and Python-string fixtures (`\.`).
The canonical `[[interfaces]]` alternation in tach.toml drifted from the
actual product set on disk. The new product:lint validator surfaced two
gaps:

- `platform_features` was listed but has no `backend/facade/contracts.py`,
  so the alternation entry could not be exercised — remove it.
- `legal_documents` has `backend/facade/contracts.py` but was absent from
  the alternation, so its facade was not reachable through the canonical
  public surface — add it.

Also reorder the remaining entries alphabetically so future drift is
easier to spot.
- `has_legacy_interface_leaks`: normalize backslashes in `from_patterns`
  before comparing to `module_path`, matching the normalization used in
  `_pattern_targets_public_surface` and `_names_from_pattern`. Without
  this, a hypothetical legacy block written as `from = ["products\\.X"]`
  would be silently skipped (greptile P1).
- Tests: collapse the nine `TestValidateFacadeAlternation` methods into
  one parametrized test row table, matching the repo convention used by
  the neighbouring `TestNamesFromPattern` and `TestLegacyInterfaceLeaks`
  classes (greptile P2, AGENTS.md "prefer parametrized tests").
- Tests: clarify the on-disk-form comment so it correctly describes
  `\\\\` source becoming two literal backslashes at runtime (Copilot).
Adding `legal_documents` to the canonical facade alternation restricts its
public surface to `backend.facade.*` and `backend.presentation.views.*`, but
core still imports `backend.admin.LegalDocumentAdmin`, `backend.models.LegalDocument`,
and `backend.presentation.webhook.legal_document_pandadoc_webhook` directly.
Without an explicit carve-out tach rejects those imports.

Add a legacy-leak `[[interfaces]]` block declaring those three surfaces as
permitted internal access — same pattern as experiments, mcp_store, and
tracing. The block should shrink as core migrates to the facade.

Per the convention documented above the legacy blocks, also remove the
no-op `backend:contract-check` script from legal_documents/package.json
so CI treats the product as non-isolated until the leaks are gone.
Removing `backend:contract-check` from `legal_documents/package.json`
left `turbo.json` overriding inputs for a task that no longer exists,
which `IsolationChainCheck` correctly flags as dead config. The override
only contained the contract-check task, so delete the whole file —
matching experiments/mcp_store/tracing, which have no turbo.json
override either.
The previous commits added `legal_documents` to the canonical facade
alternation (with a legacy-leak block, removing its contract-check script,
and deleting its turbo.json) because the validator's rule 3 — "every
product with backend/facade/contracts.py must be in the canonical
alternation" — fired on it.

That rule conflated "has facade scaffolding" with "ready for canonical
exposure", which forced a real product into a transitional state it
hadn't opted into. Drop the rule and restore legal_documents.

The validator now only catches stale entries (rules 1 + 2): names listed
that don't resolve to a real product, and names listed without
backend/facade/contracts.py. The inverse direction is left to the
per-product TachCheck (which already requires isolated products to appear
in *some* [[interfaces]] block).
…ecks

Extend product:lint --all with checks that validate tach.toml
declarations themselves, not just what tach enforces at import time.

New checks:
- No mixed facade + internal expose in a single [[interfaces]] block
  (catches the pattern where someone adds backend.facade.* next to
  backend.models.* — making isolation decorative)
- No overly broad expose patterns (backend.* matches everything)
- Alphabetical sort of canonical alternation names (prevents merge
  conflicts)
- Dangling [[interfaces]] from references (must point to existing
  [[modules]])
- Dangling [[modules]] depends_on entries (must reference existing
  modules)
@webjunkie webjunkie force-pushed the claude/validate-product-lint-tach-mrtn3 branch from d30efb6 to 5ad726b Compare May 4, 2026 12:07
@webjunkie webjunkie marked this pull request as ready for review May 4, 2026 12:26
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 4, 2026

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
tools/hogli-commands/hogli_commands/tests/test_checks.py:895-918
**`TestAlternationSorting` should be parameterised**

Both methods follow the exact same fixture pattern — create the same products, build a TOML string via `_iface`, call `validate_facade_alternation`, and assert. Only the alternation order and the expected outcome differ. Per the team rule of always preferring parameterised tests, these should be expressed as a single `@pytest.mark.parametrize` table, consistent with `TestNamesFromPattern`, `TestValidateInterfaceBlocks`, and `TestValidateTachReferences` in the same file.

### Issue 2 of 2
tools/hogli-commands/hogli_commands/product/checks.py:186-192
**`_ordered_names_from_alternation` duplicates `_names_from_pattern`**

The first four lines of both functions are identical: normalize backslashes and apply the same `^products\.\(([^)]+)\)$` regex. This violates OnceAndOnlyOnce (simplicity rule 3). A single private helper that returns the `re.Match` or both representations would eliminate the duplication.

```python
def _parse_alternation_match(pattern: str) -> re.Match | None:
    """Return the regex match for an alternation pattern, or None."""
    return re.match(r"^products\.\(([^)]+)\)$", pattern.replace("\\", ""))
```

`_names_from_pattern` and `_ordered_names_from_alternation` can then both call `_parse_alternation_match` instead of re-running the same normalization and regex.

Reviews (2): Last reviewed commit: "Merge branch 'master' into claude/valida..." | Re-trigger Greptile

@webjunkie webjunkie added the stamphog Request AI review from stamphog label May 6, 2026
Copy link
Copy Markdown

@stamphog stamphog Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR exceeds the automated size ceiling (541 lines). The substantive P1 concern about platform_features causing a hard CI failure appears addressed by the tach.toml change, but the complexity of the new facade-alternation validation logic warrants a human review to confirm correctness before merging.

@stamphog stamphog Bot removed the stamphog Request AI review from stamphog label May 6, 2026
@webjunkie webjunkie requested a review from rnegron May 6, 2026 12:01
@webjunkie webjunkie merged commit c5f8bf2 into master May 6, 2026
246 checks passed
@webjunkie webjunkie deleted the claude/validate-product-lint-tach-mrtn3 branch May 6, 2026 13:51
@deployment-status-posthog
Copy link
Copy Markdown

deployment-status-posthog Bot commented May 6, 2026

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-05-06 14:47 UTC Run
prod-us ✅ Deployed 2026-05-06 14:59 UTC Run
prod-eu ✅ Deployed 2026-05-06 15:02 UTC Run

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.

4 participants